package ticket;

import com.xr.util.DateUtil;
import com.xr.util.EmailUtils;
import com.xr.util.JSONUtil;
import com.xr.util.MultimapUtil;
import ticket.enums.SeatType;
import ticket.model.QueryItem;
import ticket.model.StationInfo;
import ticket.model.TicketDto;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;

/**
 * 12306余票查询
 *
 * 从12306证书srca.cer生成keystore文件
 * keytool -importcert -file srca.cer -keystore 12306.keystore -alias 12306
 *
 * Created by forvoyager@outlook.com on 2018-09-30 16:29.
 */
public class QueryTicket {

  public static void main(String[] args) throws Exception {

    final QueryTicket qt = new QueryTicket();
    final List<QueryItem> qis = new ArrayList<>();

     // Q1
    qis.add(new QueryItem.Builder()

    // 出发日期
    .setDepartDate("2018-11-08")

    // 贵阳 - 上海
    .setFrom_station_name("贵阳")
    .setTo_station_name("上海")

    // 座位类型
    .addFilterSeat(SeatType.YD)
    .addFilterSeat(SeatType.ED)
    .addFilterSeat(SeatType.YZ)

    // 发车时间
    .setFrom_time_start("7:00")
    .setFrom_time_end("13:00")

    // 到达时间
    .setArrive_time_start("18:00")
    .setArrive_time_end("21:00")

    // 只需要下列车次的票
//    .addTrain("K834")
//    .addTrain("G2334")

    // 邮件提醒
    .addReminderEmail("yn@y.com").build());

    // Q2
    qis.add(new QueryItem.Builder()
      .setDepartDate("2018-11-08")
      .setFrom_station_name("长沙")
      .setTo_station_name("上海")
      .addFilterSeat(SeatType.YD)
      .addFilterSeat(SeatType.ED)
      .addFilterSeat(SeatType.YZ)
      .setFrom_time_start("7:00")
      .setFrom_time_end("13:00")
      .setArrive_time_start("18:00")
      .setArrive_time_end("21:00")
      .addReminderEmail("yn@y.com").build());

    final Timer scheduler = new Timer();
    for(QueryItem qi : qis){
      scheduler.schedule(new TimerTask() {
        @Override
        public void run() {
          try {
            qt.query(qi);
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }, 2000, 10000); // 延时2s开始执行，每隔10s执行一次
    }
  }

  public QueryTicket() throws Exception {
    // 初始化站点编码
    loadStationCode();
  }

  private void query(QueryItem qi) throws Exception {
    // 查询车次信息
    String ticketJson = TicketUtil.sendRequest(String.format(
      Constant.TICKET_QUERY_URL,
      qi.getDepartDate(),
      qi.getFrom_station_code(),
      qi.getTo_station_code()
    ));

    StationInfo fromStation = null;
    StationInfo toStation = null;
    List<TicketDto> ticketInfo = parseTicketInfo(ticketJson);

    // 过滤符合要求的车次
    ticketInfo = filterCondition(qi, ticketInfo);

    // 通知
    StringBuffer msg = new StringBuffer();
    for(TicketDto dto : ticketInfo){
      fromStation = MultimapUtil.getOne(dto.getFrom_station_telecode());
      toStation = MultimapUtil.getOne(dto.getTo_station_telecode());
      msg.append(String.format(Constant.REMINDER_MESSAGE_TPL,
        dto.getStation_train_code(), fromStation.getName(), toStation.getName(), // 车次信息
        dto.getStart_time(), dto.getArrive_time(), dto.getLishi(), // 时间信息
        dto.getSwz_num(),dto.getZy_num(),dto.getZe_num(),
        dto.getGr_num(),dto.getRw_num(),dto.getSrrb_num(),dto.getYw_num(), // 卧铺
        dto.getRz_num(),dto.getYz_num(),dto.getWz_num(),dto.getQt_num() // 坐票
      ));
      msg.append("#"); // 分割符
    }
    reminder(
      String.format("余票提醒（%s-%s）", qi.getFrom_station_name(), qi.getTo_station_name()),
      msg.toString(),
      qi.getReminderEmails());

  }

  /**
   * 根据查询条件过滤出符合要求的车次
   *
   * @param qi
   * @param ticketInfo
   * @return
   */
  private List<TicketDto> filterCondition(QueryItem qi, List<TicketDto> ticketInfo) throws Exception {

    TicketDto dto = null;
    Iterator<TicketDto> it = ticketInfo.iterator();
    while (it.hasNext()) {
      dto = it.next();

      // 车次过滤
      if(qi.getTrainList().size() > 0){
        if( !qi.getTrainList().contains(dto.getStation_train_code()) ){
          it.remove();
          continue;
        }
      }

      // 发车时间过滤
      String start_time_str = TicketUtil.fillAllTimeFormat(qi.getDepartDate(), dto.getStart_time());
      if(!DateUtil.isDateBetween(
        DateUtil.timeStrToDate(start_time_str),
        DateUtil.timeStrToDate(qi.getFrom_time_start()),
        DateUtil.timeStrToDate(qi.getFrom_time_end()))){
        it.remove();
        continue;
      }

      // 到达时间过滤
      String arrive_time_str = TicketUtil.fillAllTimeFormat(qi.getDepartDate(), dto.getArrive_time());
      if(!DateUtil.isDateBetween(
        DateUtil.timeStrToDate(arrive_time_str),
        DateUtil.timeStrToDate(qi.getArrive_time_start()),
        DateUtil.timeStrToDate(qi.getArrive_time_end()))){
        it.remove();
        continue;
      }

      /**
       * 座位过滤
       * 需要过滤的所有座位类型 |
       * 当前车次可选座位类型
       * 二者 & 结果大于0说明是需要的座位
       */
      if(qi.getFilterSeat() > 0){
        if((qi.getFilterSeat() & dto.getAvailableSeat()) == 0){
          it.remove();
          continue;
        }
      }

    }

    System.out.println("符合要求的列车数："+ticketInfo.size());
    return ticketInfo;
  }

  /**
   * 从文件加载站点信息
   *
   * @throws Exception
   */
  private void loadStationCode() throws Exception {
    FileInputStream fis = new FileInputStream(this.getClass().getClassLoader().getResource("").getPath() + "station_code.properties");
    Properties prop = new Properties();
    prop.load(fis);
    fis.close();

    StationInfo station = null;
    String[] values = null;
    Set<String> keys = prop.stringPropertyNames();
    for(String key : keys){
      values = prop.getProperty(key).split("\\|");
      if(values == null || values.length == 0){ continue; }

      station = new StationInfo();
      station.setName(values[0]);
      station.setCode(key);
      station.setSuoxie(values[1]);

      MultimapUtil.put(station.getName(), station);
      MultimapUtil.put(station.getCode(), station);
    }
  }

  /**
   * 生成车次信息
   *
   * @param resp
   * @return
   * @throws IOException
   */
  private List<TicketDto> parseTicketInfo(String resp) throws IOException {

    List<TicketDto> ticketInfo = new ArrayList<>();
    if(resp == null || resp.length() < 2){return ticketInfo;}

    String arrayJson = JSONUtil.parseObject(resp).at("/data/result").toString();
    List<String> items = JSONUtil.parseList(arrayJson, String.class);
    for(String itm : items) {
      ticketInfo.add(TicketDto.build(itm));
    }

    System.out.println("查询到的列车数"+ticketInfo.size());

    return ticketInfo;
  }

  /**
   * 通知
   * @param msg
   * @throws IOException
   */
  private void reminder(String title, String msg, List<String> emails) throws IOException {
    if(msg == null || msg.length() == 0){ return; }

    // 控制台打印
    System.out.println(msg.replaceAll("#", "\n"));

    // 邮件提醒
    EmailUtils.sendMail(
      EmailUtils.MailData.New()
        .subject(title)
        .content(msg.replaceAll("#", "</br>"))
        .to(emails.toArray(new String[]{}))
    );

    // TODO 机器人提醒

  }
}